// 'ob' == offset binary
// 'tag' == Write line numbers before each line output
//
//  TODO: 目前的版本中，从bin文件提取“波形”数据、CDS处理、写入fits文件等功能，全部在
//          同一个函数中实现，代码显得臃肿，不便于后期的更新维护。
//	@2021-10-08:PL端不再将“行号”写入PS端DDR中，因此这里也不再需要使用"cfg->HAS_TAG"

#include "ccd290_extract.h"

void extract_ccd_data_ob_tag_no_shift( char fname[], char ofits[], ccd290_config* cfg ) {

	printf("--> calling %s:%s\n", __FILE__, __func__);
    printf("--> reading binary data from: %s\n", fname);

    FILE *fb = fopen(fname,"rb");

    int num = cfg->LEN*4;	// total number of 'uint32_t'
    uint32_t *regs = (uint32_t*)malloc(sizeof(uint32_t)*num);
    int num_chk = fread(regs, sizeof(uint32_t), num, fb);

    if( num_chk != num ){
    	printf("(%s:L:%d) Error in reading binary data: %s\n", __FILE__, __LINE__, fname);
    	printf("@ num_chk = %d\n", num_chk);
    	printf("@ num     = %d\n", num);
    	exit(0);
    }

    fclose(fb);

    int32_t *ch_E, *ch_F, *ch_G, *ch_H;
    ch_E = (int32_t*)malloc(sizeof(int32_t)*cfg->LEN);
    ch_F = (int32_t*)malloc(sizeof(int32_t)*cfg->LEN);
    ch_G = (int32_t*)malloc(sizeof(int32_t)*cfg->LEN);
    ch_H = (int32_t*)malloc(sizeof(int32_t)*cfg->LEN);

    int i, cnt=0;
    for(i=0; i<num; i+=4) {

        uint32_t udata_E = regs[i+0];
        uint32_t udata_F = regs[i+1];
        uint32_t udata_G = regs[i+2];
        uint32_t udata_H = regs[i+3];

    //  ====================
    //  重要:需要注意EFGH的顺序
    //  ====================
        ch_E[cnt] = udata_E;
        ch_F[cnt] = udata_F;
        ch_G[cnt] = udata_H;
        ch_H[cnt] = udata_G;
        
/*        if( i <= 10*4 ){*/
/*        	printf("E = %8d F = %8d G = %8d H = %8d\n", udata_E, udata_F, udata_G, udata_H);*/
/*        }*/

        cnt++;
    }

//	CDS
/*	uint16_t *ccd = (uint16_t*)malloc(sizeof(uint16_t)*cfg->N_ROW*cfg->N_COL*4);*/
/*    uint32_t *ccd = (uint32_t*)malloc(sizeof(uint32_t)*cfg->N_ROW*cfg->N_COL*4);*/
    float *ccd = (float*)malloc(sizeof(float)*cfg->N_ROW*cfg->N_COL*4);
    
    int i_max = cfg->N_ROW * cfg->N_COL * 4;
    for( i = 0; i < i_max; i++ ) {
        ccd[i] = 0;
    }

//  get settings from ccd290_config * cfg
	uint idx_offset = cfg->idx_offset;

    printf("idx_offset = %d\n", cfg->idx_offset);

    int row_cnt=0, col_cnt=0;
    int idx;

	/************************************************************************
		CCD数据矩阵对应的通道分布，为了使图像拼接完整，在下面的代码中需要交换G、H通道的数据
		E | F
		--|--
		H | G
	*************************************************************************/

	int cnt_tmp = 0; // for debug

	double nsample = cfg->cds_weight;
/*	double nsample_per_reg = 12.0;*/
    for( idx = idx_offset; idx < cfg->LEN; idx += cfg->SAMP_NUM_PER_REG) {
    
	    int idxE = row_cnt * cfg->N_COL * 2 + col_cnt;
	    int idxF = row_cnt * cfg->N_COL * 2 + (cfg->N_COL * 2 - col_cnt - 1);
	    int idxG = (cfg->N_ROW*2 - row_cnt - 1) * cfg->N_COL * 2 + col_cnt;
	    int idxH = (cfg->N_ROW*2 - row_cnt - 1) * cfg->N_COL * 2 + (cfg->N_COL * 2 - col_cnt - 1);

    //  an offset is added to the difference between reference volt and signal volt to avoid negative values

/*		int tmp_E = (ch_E[idx] / nsample) + cfg->cds_offset;*/
/*		int tmp_F = (ch_F[idx] / nsample) + cfg->cds_offset;*/
/*		int tmp_G = (ch_G[idx] / nsample) + cfg->cds_offset;*/
/*		int tmp_H = (ch_H[idx] / nsample) + cfg->cds_offset;*/

/*		ccd[idxE] = (uint16_t)tmp_E;*/
/*		ccd[idxF] = (uint16_t)tmp_F;*/
/*		ccd[idxG] = (uint16_t)tmp_G;*/
/*		ccd[idxH] = (uint16_t)tmp_H;*/

		ccd[idxE] = (ch_E[idx] / nsample) + cfg->cds_offset;
		ccd[idxF] = (ch_F[idx] / nsample) + cfg->cds_offset;
		ccd[idxG] = (ch_G[idx] / nsample) + cfg->cds_offset;
		ccd[idxH] = (ch_H[idx] / nsample) + cfg->cds_offset;

/*		if( cnt_tmp < 1000 ){*/
/*			printf("ccd[idxE] = %7d ccd[idxF] = %7d ccd[idxG] = %7d ccd[idxH] = %7d\n", */
/*					ccd[idxE], ccd[idxF], ccd[idxG], ccd[idxH]);*/
/*			cnt_tmp++;*/
/*		}*/

    	col_cnt++;  // 必须先+1,然后再进行判断
        if( col_cnt >= cfg->N_COL ) {
            col_cnt -= cfg->N_COL;
            row_cnt++;
        }
    }

//	===================================================
//  write CDS process data into fits
    fitsfile *fptr;
    int status;
    long fpixel = 1, naxis = 2, nelements, exposure;
    
    long naxes[2] = {(cfg->N_COL + cfg->HAS_TAG)*2, cfg->N_ROW * 2}; // image is 300 pixel wide by 200 rows
    
    if( cfg->include_line_num == 0 ){
    	naxes[0] = cfg->N_COL * 2;
    	naxes[1] = cfg->N_ROW * 2;
    }

    status = 0;
    
	fits_create_file(&fptr, ofits, &status); /* create new file */

    /*Create the primary array image (16-bit short uinteger pixels) */
/*    	fits_create_img(fptr, SHORT_IMG, naxis, naxes, &status);*/
/*    fits_create_img(fptr, USHORT_IMG, naxis, naxes, &status);*/
    
/*    fits_create_img(fptr, ULONG_IMG, naxis, naxes, &status);*/
/*    fits_create_img(fptr, LONG_IMG, naxis, naxes, &status);*/
    fits_create_img(fptr, FLOAT_IMG, naxis, naxes, &status);

    /*Write a keyword; must pass the ADDRESS of the value */
    exposure = 3.;
    fits_update_key(fptr, TLONG, "EXPOSURE", &exposure, "Total Exposure Time", &status);

    long speed = 636;
    fits_update_key(fptr, TLONG, "RD_SPD", &speed, "READOUT SPEED (KHz)", &status);

    double temp = -96.5;
    fits_update_key(fptr, TDOUBLE, "TEMP", &temp, "CCD operating temperature", &status);

    double v_rst_gate = 12;
    fits_update_key(fptr, TDOUBLE, "RST_GATE", &v_rst_gate, "RESET GATE (V)", &status);

    double v_rst_dr = 16.25;
    fits_update_key(fptr, TDOUBLE, "RST_DR", &v_rst_dr, "RESET DRAIN (V)", &status);

    double v_out_drain = 30.5;
    fits_update_key(fptr, TDOUBLE, "OUT_DRN", &v_out_drain, "OUTPUT DRAIN (V)", &status);
    
    double v_dp_drain = 29;
    fits_update_key(fptr, TDOUBLE, "DP_DRAIN", &v_dp_drain, "DUMP DRAIN (V)", &status);

    double v_op_1v = 0.5;
    fits_update_key(fptr, TDOUBLE, "OP_1V", &v_op_1v, "OP_1V (V)", &status);


    // 写入头文件信息
    


    /* Write the array of integers to the image */
    nelements = naxes[0] * naxes[1];
    
//	==============================================================================
/*	fits_write_img(fptr, TUSHORT, fpixel, nelements, ccd, &status);*/
/*	fits_write_img(fptr, TUINT, fpixel, nelements, ccd, &status);*/
	fits_write_img(fptr, TFLOAT, fpixel, nelements, ccd, &status);
//	==============================================================================

    fits_close_file(fptr, &status);

    printf("--> data saved into fits: %s\n", ofits);

    fits_report_error(stderr, status);
//	===================================================

    free(ch_E);
    free(ch_F);
    free(ch_G);
    free(ch_H);

    free(regs);
    free(ccd);
}


